package com.duobaoyu.dby.supply.biz.client.boundary.channel;

import com.duobaoyu.dby.channel.adapter.bean.config.*;
import com.duobaoyu.dby.channel.adapter.enums.biz.config.GlobalErrorCodeEnum;
import com.duobaoyu.dby.channel.adapter.service.AbstractSupplyChannelConfig;
import com.duobaoyu.dby.supply.biz.client.resource.ResourceApiClient;
import com.duobaoyu.dby.supply.biz.client.resource.bean.bo.*;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.ChannelRuleDTO;
import com.duobaoyu.dby.supply.biz.client.resource.bean.dto.StateInfoDTO;
import com.duobaoyu.dby.supply.biz.exception.SupplyChainBizException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.script.ScriptException;
import java.util.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @version 1.0.0
 * @ClassName SupplyChaninChannelConfig
 * @Description 渠道对接配置
 * @createTime 10:33:00 2023/09/26
 */
@Primary
@Component
@RequiredArgsConstructor
public class SupplyChainChannelConfig extends AbstractSupplyChannelConfig {

	private final ResourceApiClient resourceApiClient;
	private final ThreadPoolExecutor supplyChannelThreadPool;

	@PostConstruct
	public void init() {
		this.register(this.supplyChannelThreadPool);
	}

	@Override
	public ChannelConfig channelConfig(String channelCode,String configUniqueKey) {
		if(StringUtils.isNotBlank(configUniqueKey)) {
			SupplyChainBizException.fail("不支持对接渠道配置唯一key设置");
			return null;
		} else {
			ChannelConfigBO channelConfig = resourceApiClient.channelConfig(channelCode);
			if (Objects.isNull(channelConfig)) {
				return null;
			}
			List<ChannelConfigBO.ParamConfig> paramConfigs = Optional.of(channelConfig).map(ChannelConfigBO::getIfParams).orElse(Collections.emptyList());
			return ChannelConfig
					.builder()
					.channelCode(channelConfig.getChannelCode())
					.channelName(channelConfig.getChannelName())
					.ifParams(paramConfigs.stream().map(param -> ChannelConfig.ParamConfig
									.builder()
									.name(param.getName())
									.description(param.getDescription())
									.field(param.getField())
									.fieldValue(param.getFieldValue())
									.type(param.getType())
									.build())
							.collect(Collectors.toList()))
					.status(channelConfig.getStatus())
					.build();
		}
	}

	@Override
	public List<DictionaryConfig> getCacheDictionaryItemByDictionaryCode(String dictionaryCode) {
		List<DictionaryConfigBO> dictionaryConfigs = resourceApiClient.dictionaryByCode(dictionaryCode);
		if (CollectionUtils.isEmpty(dictionaryConfigs)) {
			return Collections.emptyList();
		}
		return dictionaryConfigs.stream()
				.map(dictionaryConfig -> DictionaryConfig
						.builder()
						.itemText(dictionaryConfig.getItemText())
						.itemValue(dictionaryConfig.getItemValue())
						.description(dictionaryConfig.getDescription())
						.build())
				.collect(Collectors.toList());
	}

	@Override
	public ExceptionMapping toLocalExceptionCodeMapping(String channelCode, String channelExceptionCode, String channelExceptionMessage) throws ScriptException {
		ChannelRuleDTO channelRule = ChannelRuleDTO.builder()
				.channelCode(channelCode)
				.channelExceptionCode(channelExceptionCode)
				.channelExceptionMessage(channelExceptionMessage)
				.build();
		ChannelRuleBO localExceptionRule = resourceApiClient.toLocalExceptionRule(channelRule);
		return ExceptionMapping.builder()
				.localExceptionCode(Optional.ofNullable(localExceptionRule).map(ChannelRuleBO::getLocalExceptionCode).orElse(GlobalErrorCodeEnum.CHANNEL_ERROR.getCode().toString()))
				.localExceptionName(Optional.ofNullable(localExceptionRule).map(ChannelRuleBO::getLocalExceptionName).orElse(GlobalErrorCodeEnum.CHANNEL_ERROR.getMsg()))
				.exceptionDate(Optional.ofNullable(localExceptionRule).map(ChannelRuleBO::getExceptionDate).orElse(Collections.emptyList()))
				.build();
	}

	@Override
	public State getStateInfo(String channelCode, Class<?> clzEnum, Object mappingValue) {
		StateInfoDTO info = StateInfoDTO.builder()
				.channelCode(channelCode)
				.classType(Optional.ofNullable(clzEnum).map(Class::getName).orElse(null))
				.channelValue(mappingValue)
				.build();
		StateInfoBO stateInfo = resourceApiClient.getStateInfo(info);
		if (Objects.isNull(stateInfo)) {
			return null;
		}
		Map<String, StateInfoBO> stateInfoMap = Optional.ofNullable(stateInfo).map(StateInfoBO::getMappingMap).orElse(Maps.newHashMap());
		Map<String, State> stateMap = Maps.newHashMap();
		for (Map.Entry<String, StateInfoBO> stringStateInfoEntry : stateInfoMap.entrySet()) {
			String code = stringStateInfoEntry.getKey();
			StateInfoBO state = stringStateInfoEntry.getValue();
			if (Objects.nonNull(state)) {
				State stat = State.builder()
						.channelCode(state.getChannelCode())
						.stateCode(state.getStateCode())
						.stateMappingCode(state.getStateMappingCode())
						.stateMappingName(state.getStateMappingName())
						.stateMappingValue(state.getStateMappingValue())
						.classType(state.getClassType())
						.mappingMap(Maps.newHashMap())
						.build();
				stateMap.put(code, stat);
			}
		}
		return State.builder()
				.channelCode(stateInfo.getChannelCode())
				.stateCode(stateInfo.getStateCode())
				.stateMappingCode(stateInfo.getStateMappingCode())
				.stateMappingName(stateInfo.getStateMappingName())
				.stateMappingValue(stateInfo.getStateMappingValue())
				.classType(stateInfo.getClassType())
				.mappingMap(stateMap)
				.build();
	}

	@Override
	public ChannelPrefreightConfig channelPrefreightConfig(String channelCode) {
		PrefreightConfigBO prefreightConfig = resourceApiClient.queryPrefreightConfig(channelCode);
		PrefreightConfigBO.Prefreight prefreight = Optional.ofNullable(prefreightConfig).map(PrefreightConfigBO::getPrefreight).orElse(null);
		List<PrefreightConfigBO.Prefreight.PrefreightParam> prefreightParams = Optional.ofNullable(prefreight).map(PrefreightConfigBO.Prefreight::getFreightParam).orElse(Lists.newArrayList());
		return Objects.isNull(prefreight) ? null : ChannelPrefreightConfig.builder()
				.freightFilter(prefreight.getFreightFilter())
				.freightWay(prefreight.getFreightWay())
				.freightParam(prefreightParams.stream().map(param -> ChannelPrefreightConfig.PrefreightParam
						.builder()
								.startValue(param.getStartValue())
								.endValue(param.getEndValue())
								.freightValue(param.getFreightValue())
								.isSort(param.getIsSort())
						.build())
						.collect(Collectors.toList()))
				.build();
	}
}
